package net.omnivention.wulumuqi.html;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import net.omnivention.wulumuqi.HtmlDocument;

import org.jdom.Content;
import org.jdom.Element;

public class Table extends HtmlElement {
	private TableModel model;

	public Table() {
		super("table");
		setNamespace(HtmlElementFactory.htmlns);
	}

	public TableModel getModel() {
		return model;
	}

	public void setModel(TableModel model) {
		this.model = model;
		generateTable();
	}

	private void generateTable() {
		HttpServletRequest req = ((HtmlDocument)this.getDocument()).getRequest();
		String mr = getAttributeValue("maxRow");
		String sortableString = getAttributeValue("sortable");
		String orderString = req.getParameter("order");
		String columnString = req.getParameter("column");
		
		boolean sortable = false;
		int maxRow = 0;
		int page = 0;
		int column = 0; 
		

		try {
			page = Integer.parseInt(req.getParameter("page"));
		} catch (Exception e) {

		}

		try {
			maxRow = Integer.parseInt(mr);
		} catch (Exception e) {

		}

		try{
			column = Integer.parseInt(columnString);
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		if(sortableString != null){
			sortable = Boolean.parseBoolean(sortableString);
		}
		
		if(orderString != null){
			orderString = orderString.toLowerCase();
		} else {
			orderString = "asc";
		}
		
		int rowCount = model.getRowCount();
		int columnCount = model.getColumnCount();

		// assume 0 or less means display all rows
		if (maxRow <= 0) {
			maxRow = rowCount;
		}
		
		// global if for valid pages only
		if (rowCount - maxRow * page > 0 && rowCount - maxRow * page <= rowCount) {
			
			// populate data table for possible sorting
			ArrayList<TableRow> data = new ArrayList<TableRow>();
			//for(int i=0; i<rowCount; i++){
			for (int i = (maxRow == rowCount) ? 0 : maxRow * page; i < rowCount && i < (maxRow + maxRow * page); i++){
				TableRow row = new TableRow();
				for(int j=0; j<columnCount; j++){
					row.add(model.getContentAt(i, j));
				}
				data.add(row);
			}
			
			// SORT
			// if table has rows and sortable insert a row for sort manipulation
			if (sortable) {		
				
				Element header = null;
				try{
					header = this.selectNode("html:thead/html:tr[1]");
				} catch (Exception e) {
					// TODO: handle exception
				}
				
				// prepare request string for links
				String linkString = req.getRequestURL().toString();
				if (req.getParameterNames().hasMoreElements()) {
					linkString += "?";
				}
				for (Object par : req.getParameterMap().keySet()) {
					if (!par.equals("column") && !par.equals("order")) {
						linkString += par + "="
								+ req.getParameter(par.toString()) + "&";
					}
				}
				
				//Element tr = HtmlElementFactory.createElement("tr");
				List colHeaders = header.getChildren();
				for (int j = 0; j < columnCount; j++) {
					
					Element colHeader = null;
					if(j<colHeaders.size()){
						colHeader = (Element)colHeaders.get(j);
					}
					
					Element link = null;
					if(column == j){
						// set column to be sorted by
						for(int k=0; k<data.size(); k++){
							data.get(k).setColumn(column);
						}
						
						Collections.sort(data);
						if(orderString.equals("asc")){
							link = new A(linkString + "column=" + j + "&order=desc", colHeader.getText());
						}
						// any other order requests will be interpreted as asc
						else{
							Collections.reverse(data);
							link = new A(linkString + "column=" + j + "&order=asc", colHeader.getText());
						}
						Element b = new Element("b");
						b.setContent(link);
						link = b;
					}
					else{
						link = new A(linkString + "column=" + j + "&order=asc", colHeader.getText());
					}
					
					if(colHeader != null){
						colHeader.setContent(link);
					}
				}
			}

			// ROW DATA
			// the data rows inserted here			
			Element tbody = selectNode("html:tbody");
			for (int i = (maxRow == rowCount || sortable)? 0 : maxRow * page; 
					(sortable && i<data.size()) || (!sortable && i < rowCount && i < (maxRow + maxRow * page)); 
					i++){					
				Element tr = HtmlElementFactory.createElement("tr");
				for (int j = 0; j < columnCount; j++) {
					Content c = (sortable)?data.get(i).get(j):model.getContentAt(i, j);
					Element td = HtmlElementFactory.createElement("td");
					td.setContent(c);
					tr.addContent(td);
				}
				tbody.addContent(tr);
			}


			// PAGING
			if (maxRow < rowCount) {
				// prepare request string for links
				String linkString = req.getRequestURL().toString();
				if (req.getParameterNames().hasMoreElements()) {
					linkString += "?";
				}
				for (Object par : req.getParameterMap().keySet()) {
					if (!par.equals("page")) {
						linkString += par + "="
								+ req.getParameter(par.toString()) + "&";
					}
				}

				Element tr = HtmlElementFactory.createElement("tr");
				Element td = HtmlElementFactory.createElement("td");

				// put previous or not
				if (page != 0 && page * maxRow < rowCount) {
					td.addContent(new A(linkString + "page=" + (page - 1),
							"<<previous " + maxRow));					
				}

				// pages
				td.addContent("[");
				int	lastPage = (rowCount%maxRow==0)?rowCount/maxRow:rowCount/maxRow+1;
				int pages = ((int)page/10)*10;
				pages += (pages + 10)<=lastPage?10:lastPage%10;
				
				for(int i=((int)page/10)*10; i<lastPage && i<pages; i++){
					if(i!=page){
						td.addContent(new A(linkString + "page=" + i, ""+i));
					} else {
						Element b = new Element("b");
						b.setText(""+i);
						td.addContent(b);
					}
				}
				td.addContent("]");
				

				// put next or not
				if ((page + 1) * maxRow < rowCount) {
					td.addContent(new A(linkString + "page=" + (page + 1),	"next "
						+ (((rowCount - (maxRow + maxRow * page)) < maxRow) ?
							(rowCount - (maxRow + maxRow * page)): maxRow) + ">>"));
				}

				td.setAttribute("colspan", Integer.toString(columnCount));
				tr.setContent(td);
				addContent(tr);
			}
		}
	}

}


class TableRow extends ArrayList<Content> implements Comparable<TableRow>{
	private int column;
	
	public void setColumn(int newColumn){
		column = newColumn;
	}
	
	public int getColumn(){
		return column;
	}
	
	public int compareTo(TableRow another) {
		Integer a = null;
		Integer b = null;
		try {
			a = Integer.parseInt(this.get(column).getValue());
			b = Integer.parseInt(another.get(another.getColumn()).getValue());
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		// if comparing integers
		if(a != null && b != null){
			return a.compareTo(b);
		} else { // or strings
			return this.get(column).getValue().compareTo(another.get(another.getColumn()).getValue());
		}
	}
}
